package column


import (
	"github.com/treelab/updatecolumn/models"
)

  func instanceType() int32 {
    return models.Select
  }

  deleteColumnEdges(command: UpdateColumn_v2, o: CommonOptions) {
    const { column } = command;
    const options = (command.columnConfig as SelectionColumnConfig).options! || [];
    const columnOptions = column.hasColumnOption.get();

    // remove options
    const optionsToRemove = _.differenceBy(
      columnOptions,
      options,
      item => (item as ColumnOption).uid || (item as OptionInput).optionId,
    );
    if (optionsToRemove.length) {
      _.forEach(optionsToRemove, optionToRemove =>
        this.getRemoveColumnOptionQuads({ ...command, option: optionToRemove }, o),
      );
    }
    return this;
  }

  public hasNothingToUpdate(command: UpdateColumn_v2) {
    const { column } = command;
    const selectColumnConfig = command.columnConfig as SelectionColumnConfig;
    const options = selectColumnConfig.options;
    const columnOptions = column.hasColumnOption.get();
    const compare = () => {
      if (options?.length !== columnOptions.length) {
        return false;
      }
      let result = true;
      _.forEach(options, (option: ColumnOption, optionIndex: number) => {
        const index = columnOptions.findIndex(
          columnOPtion => columnOPtion.name === option.name && columnOPtion.color === option.color,
        );
        if (index === -1) {
          result = false;
          return false;
        }
        if (index !== optionIndex) {
          result = false;
          return false;
        }
      });
      return result;
    };
    return column.columnType === this.instanceType && compare();
  }

  async updateColumn(
    command: UpdateColumn_v2,
    o: CommonOptions,
    helper: { rows?: Row[]; columnCopy?: Column; referenceColumns?: Column[]; userGroup?: any },
  ) {
    await super.updateColumn(command, o, helper);

    const { column, columnConfig } = command;
    const { options, type } = columnConfig as SelectionColumnConfig;
    const { columnType } = column;

    const columnOptions = column.hasColumnOption.get();
    if (columnType !== type) {
      _.forEach(columnOptions, colOption => (colOption.columnType = type));
    }

    // add options
    _.forEach(options, (optionToAdd: ColumnOption, index: number) =>
      this.addOptions({ command, option: optionToAdd, index }, o),
    );
    return this;
  }

  addColumnUpdateEvent(command: UpdateColumn_v2, o: CommonOptions, updateColumnHelper: UpdateColumnHelper = {}) {
    const { workspaceId, coreId, tableId, columnConfig, column, _metadata } = command;
    column.columnType = columnConfig.type;
    const { columnId } = updateColumnHelper;
    o.events.addEvents(
      new ColumnConfigUpdated(workspaceId, coreId, tableId, column.uid ?? columnId!, columnConfig, _metadata),
      ['optionId'].concat(column.uid ? ['columnId'] : []),
    );
  }

  async convertColumn(
    command: UpdateColumn_v2,
    o: CommonOptions,
    helper: { rows?: Row[]; columnCopy?: Column; referenceColumns?: Column[]; userGroup?: any },
  ) {
    const { column } = command;

    const emptyCells = ![ColumnType.MULTI_SELECT, ColumnType.SELECT].includes(column.columnType);
    await this.defaultConvert({ command, emptyCells }, o, helper);
    return this;
  }

  addOptions(
    { option, command, index }: { option: OptionInput; command: UpdateColumn_v2; index: number },
    o: CommonOptions,
  ) {
    const {
      column,
      columnConfig: { type },
    } = command;

    let _option;
    if (!option.optionId) {
      _option = o.ormTransaction.nodeFor(ColumnOption);
      option.optionId = this.getNodeTempId(_option);
      _option.type = GraphNodeTypes.COLUMN_OPTION;
      _option.columnType = type;
      _option.fromColumn.add(column);
      column.hasColumnOption.withFacet(new OrderFacet({ order: column.hasColumnOption.get().length })).add(_option);
    } else {
      _option = column.hasColumnOption.get().find(colOption => colOption.uid === option.optionId);
      column.hasColumnOption.withFacet(new OrderFacet({ order: index })).update(_option!);
    }
    if (_option) {
      if (_option.name !== option.name) {
        _option.name = option.name;
      }
      if (_option.color !== option.color) {
        _option.color = option.color;
      }
    }
  }

  getRemoveColumnOptionQuads(command: RemoveColumnOption_v2, o: CommonOptions) {
    const { workspaceId, coreId, tableId, column, option, _metadata } = command;

    // remove cell options
    const cells = column.hasCell.get();
    const hasOptionCells = cells.filter(
      cell => cell.hasColumnOption.get().filter(cellOption => cellOption.uid === option.uid).length,
    );
    if (hasOptionCells.length) {
      _.forEach(hasOptionCells, cell => {
        o.delQuads.push(
          ...this.dgraphHelperService.getRemoveEdgeQuads(cell.uid!, Relation.HAS_COLUMN_OPTION, option.uid),
        );
        cell.hasColumnOption.delete(option);
      });
    }

    // remove kanban
    const columnOption = column.hasColumnOption
      .get()
      .find(colOption => colOption.hasLane.get().filter(lane => lane.hasKanbanView.get().length).length);
    if (columnOption) {
      const lanes = columnOption.hasLane.get();
      lanes.forEach(lane => {
        const views = lane.hasKanbanView.get();
        _.forEach(views, view => {
          o.delQuads.push(...this.dgraphHelperService.getRemoveEdgeQuads(view.uid!, Relation.HAS_LANE, lane.uid));
          view.hasLane.delete(lane);
        });
        o.delQuads.push(...this.dgraphHelperService.getRemoveObjectQuads(lane.uid!));
      });
    }
    // remove column option
    o.delQuads.push(...this.dgraphHelperService.getRemoveObjectQuads(option.uid!));
    o.delQuads.push(
      ...this.dgraphHelperService.getRemoveEdgeQuads(column.uid!, Relation.HAS_COLUMN_OPTION, option.uid),
    );
    column.hasColumnOption.delete(option);
    o.events.addEvents(new ColumnOptionRemoved(workspaceId, coreId, tableId, column.uid!, option.uid!, _metadata));
  }

  public getColumnTypeOptions(column: Column, columnConfig?: any): { name: any; type: any; typeOptions: string } {
    const result = super.getColumnTypeOptions(column, columnConfig);
    if (columnConfig) {
      return result;
    }
    const typeOptions = JSON.parse(result.typeOptions);
    typeOptions.options = column.hasColumnOption.get() || [];
    return Object.assign(result, { typeOptions: JSON.stringify(typeOptions) });
  }

